# coding:utf-8
from typing import Union

from PySide6.QtCore import QSizeF, Qt, QUrl, Signal, QEvent, QTimer
from PySide6.QtGui import QPainter, QKeyEvent, QAction
from PySide6.QtMultimedia import QMediaPlayer
from PySide6.QtMultimediaWidgets import QGraphicsVideoItem
from PySide6.QtWidgets import QGraphicsScene, QGraphicsView, QVBoxLayout, QGraphicsBlurEffect
from qeventmanager import qevent_manager
from qfluentwidgets import MessageDialog, FluentStyleSheet, FluentIcon, TransparentToolButton, \
    IndeterminateProgressRing, ToolButton

from common import signalBus
from common.server import VideoModel, BananaServer
from components import ImageLabel, TagLabel
from .play_bar import PlayBar


class VideoInterface(QGraphicsView):
    fullScreenChanged = Signal(bool)  # enter/exit full screen
    closeSignal = Signal(object)  # close window
    showSignal = Signal(object, object)  # show window

    def __init__(self, parent=None):
        super().__init__(parent)
        self.model = None  # type: VideoModel

        self.timer = QTimer(self)
        self.returnBtn = ToolButton(FluentIcon.RETURN, self)
        self.titleLabel = TagLabel(self)
        self.progressRing = IndeterminateProgressRing(self)
        self.backgroundLabel = ImageLabel(self)

        self.vBoxLayout = QVBoxLayout(self)
        self.videoItem = QGraphicsVideoItem()
        self.graphicsScene = QGraphicsScene(self)
        self.playBar = PlayBar(self)
        self.toggleFullScreenAct = QAction(self, shortcut=Qt.Key.Key_F11, triggered=self.__toggleFullScreen)

        self.__initWidgets()
        self.__connectSignals()

    def __initWidgets(self):
        self.setMouseTracking(True)
        self.setScene(self.graphicsScene)
        self.graphicsScene.addItem(self.videoItem)
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setRenderHints(
            QPainter.RenderHint.Antialiasing | QPainter.RenderHint.SmoothPixmapTransform | QPainter.RenderHint.LosslessImageRendering)

        self.player.setVideoOutput(self.videoItem)

        self.addActions([self.toggleFullScreenAct])
        FluentStyleSheet.MEDIA_PLAYER.apply(self)

        self.timer.setInterval(3000)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.playBar.hide)

        self.returnBtn.setGeometry(5, 5, 40, 36)
        self.returnBtn.clicked.connect(self.__onClosed)
        self.titleLabel.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
        self.titleLabel.setFixedHeight(36)
        self.titleLabel.setGeometry(50, 5, 400, 36)

        self.progressRing.setFixedSize(60, 60)
        self.progressRing.setVisible(False)

        self.backgroundLabel.setScaledContents(True)
        self.backgroundLabel.setEnableMask(True)
        blurEffect = QGraphicsBlurEffect(self)
        blurEffect.setBlurHints(QGraphicsBlurEffect.BlurHint.QualityHint)
        blurEffect.setBlurRadius(10)
        self.backgroundLabel.setGraphicsEffect(blurEffect)
        self.backgroundLabel.lower()

    def setTitle(self, text: str):
        self.titleLabel.setText(text)
        self.titleLabel.adjustSize()

    def title(self):
        return self.titleLabel.text()

    def __connectSignals(self):
        self.player.mediaStatusChanged.connect(self.__onMediaStatusChanged)
        self.player.errorOccurred.connect(self.__onPlayerError)
        self.playBar.downloadButton.clicked.connect(lambda _: signalBus.downloadSig.emit(self.model))
        self.playBar.fullScreenButton.clicked.connect(self.__toggleFullScreen)
        signalBus.videoUrlChanged.connect(self.load)

    def load(self, model: VideoModel):
        """ 加载视频 """
        self.model = model
        self.showSignal.emit(self, model)
        self.backgroundLabel.setUrl(model.cover_url)
        self.setTitle(model.title)

        qevent_manager.addTask(BananaServer.replay, model.vod_id, model.is_mini, slot=self.setVideo)

    def setVideo(self, url: Union[str, QUrl] = None):
        """ set the video to play """
        self.model.m3u8_url = url
        # if url:
        #     url = 'https://svipsvip.ffzy-online5.com/20250708/42865_f8b1611e/3000k/hls/mixed.m3u8'
        self.player.setSource(QUrl(url))
        self.videoItem.setSize(QSizeF(self.size()))
        self.fitInView(self.videoItem, Qt.AspectRatioMode.KeepAspectRatio)
        self.resetTransform()
        self.play()

    def hideEvent(self, e):
        self.pause()
        e.accept()

    def wheelEvent(self, e):
        return

    def enterEvent(self, e):
        self.playBar.show()

    def leaveEvent(self, e):
        self.timer.start()

    def play(self):
        self.playBar.play()

    def pause(self):
        self.playBar.pause()

    def stop(self):
        self.playBar.stop()

    def togglePlayState(self):
        """ toggle play state """
        if self.player.isPlaying():
            self.pause()
        else:
            self.play()

    def resizeEvent(self, e):
        super().resizeEvent(e)
        self.videoItem.setSize(QSizeF(self.size()))
        self.setSceneRect(0, 0, self.width(), self.height())

        self.playBar.move(0, self.height() - self.playBar.height())
        self.playBar.setFixedSize(self.width(), self.playBar.height())
        self.progressRing.move((self.width() - self.progressRing.width()) // 2,
                               (self.height() - self.progressRing.height()) // 2)
        self.backgroundLabel.setGeometry(0, 0, self.width(), self.height())

    def eventFilter(self, obj, e: QEvent):
        if obj is self.playBar:
            if e.type() == QEvent.Type.Hide:
                self.setCursor(Qt.CursorShape.BlankCursor)
            elif e.type() == QEvent.Type.Show:
                self.setCursor(Qt.CursorShape.ArrowCursor)

        return super().eventFilter(obj, e)

    def keyPressEvent(self, e: QKeyEvent):
        if e.key() == Qt.Key.Key_Left:
            self.playBar.skipBack(10000)
        elif e.key() == Qt.Key.Key_Right:
            self.playBar.skipForward(10000)
        elif e.key() == Qt.Key.Key_Up:
            self.playBar.volumeButton.setVolume(self.player.volume() + 1)
        elif e.key() == Qt.Key.Key_Down:
            self.playBar.volumeButton.setVolume(self.player.volume() - 1)

        return super().keyPressEvent(e)

    def closeEvent(self, e):
        """ 关闭时暂停视频 """
        self.pause()
        e.accept()

    def mouseMoveEvent(self, e):
        self.playBar.show()
        self.timer.stop()
        self.timer.start(3000)

    def mousePressEvent(self, e):
        if e.button() == Qt.MouseButton.LeftButton:
            if self.playBar.isVisible():
                self.playBar.hide()
            else:
                self.playBar.show()

    @property
    def player(self):
        return self.playBar.player

    def __onPlayerError(self, error: QMediaPlayer.Error, errorString: str):
        """ play error slot """
        if error == QMediaPlayer.Error.NoError:
            return
        messageMap = {
            QMediaPlayer.Error.ResourceError: "无法解析媒体资源.",
            QMediaPlayer.Error.FormatError: "不支持媒体资源的格式.",
            QMediaPlayer.Error.NetworkError: "发生网络错误",
            QMediaPlayer.Error.AccessDeniedError: "没有播放媒体资源的适当权限."
        }
        w = MessageDialog('视频发生错误', messageMap[error], self.window())
        w.yesButton.hide()
        w.exec()

    def __toggleFullScreen(self):
        """ toggle full screen """
        isFull = self.window().isFullScreen()
        if isFull:
            self.playBar.fullScreenButton.setIcon(FluentIcon.FULL_SCREEN)
            self.returnBtn.show()
            self.titleLabel.show()
        else:
            self.playBar.fullScreenButton.setIcon(FluentIcon.BACK_TO_WINDOW)
            self.returnBtn.hide()
            self.titleLabel.hide()
        self.fullScreenChanged.emit(not isFull)

    def __onMediaStatusChanged(self, status: QMediaPlayer.MediaStatus):
        if status == QMediaPlayer.MediaStatus.LoadedMedia:
            self.progressRing.setVisible(False)
        elif status == QMediaPlayer.MediaStatus.LoadingMedia:
            self.progressRing.setVisible(True)
        elif status == QMediaPlayer.MediaStatus.StalledMedia:
            self.progressRing.setVisible(True)
        if status != QMediaPlayer.MediaStatus.EndOfMedia:
            return

        self.playBar.playButton.setPlay(False)

    def __onClosed(self):
        self.setVideo('')
        self.close()
        self.closeSignal.emit(self)
